/*
 * Engine.h
 *
 *  Created on: Oct 19, 2012
 *      Author: johnny
 */

#pragma once

#ifndef ENGINE_H_
#define ENGINE_H_

#include <stack>

#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>
#include <boost/pool/object_pool.hpp>

#include "definitions.h"
#include "interfaces.h"
#include "GenericMI.h"
#include "ConfigurationManager.h"
#include "Logger.h"
#include "measurement/MeasBase.hpp"

#define ENGINE_ENTITY_NAME L"Engine"

namespace core {

class Engine: public interfaces::DistributorIfc {
private:
	Engine();
    Engine(Engine const&): inputHandler(GenericMI::getInstance()), cfgManager(ConfigurationManager::getInstance()),
    		running(true), currentIndex(0) {}
    void operator=(Engine const&) {}

    GenericMI& inputHandler;
    ConfigurationManager& cfgManager;
	boost::object_pool<DataPackage> dataPool;
    MOStorage measurementObjects;

    std::stack<unsigned char> indexes;
    bool running;
    unsigned char currentIndex;
    unsigned short moHandle;

    void dumpIndex(unsigned char index);

    bool findFiles(const boost::filesystem::path& dir,
                const std::wstring& fileExt,
                std::list<boost::filesystem::path>& libs);

    /**
     * @brief Check whether the given path points to a valid MO
     */
    boost::shared_ptr<measurement::MeasurementObject> isMO(const boost::filesystem::path &p);

    /**
     * @brief Get Instance of given MO
     */
    measurement::MeasBase* getInstanceOfMO(boost::shared_ptr<measurement::MeasurementObject> mo);
public:
    virtual ~Engine();

    /**
     * @brief Get the available MOs list
     */
    const MOStorage& getMOList();

    /**
     * @brief Get next MO index available
     * @return index
     */
    unsigned char getIndex();

    /**
     * @brief Scan directories for MOs
     * @return Whether scan succeded or not
     */
    bool scanMOs(const boost::filesystem::path&);

    /**
     * @brief Add a scanned MO to the known MOs list
     */
    void addScannedMO(measurement::MeasurementObject *);

    /**
     * @brief Load system MOs
     */
    void loadSysMOs();

    /**
     * @brief Load MO from available MO list given it's index
     */
    void loadMOByIndex(unsigned char index);

    /**
     * @brief Unload MO from loaded list
     */
    void removeMOByMeasIndex(unsigned short index);

    /**
     * @brief Handle distribution of package to consumers
     */
    void distribute(const unsigned short measIndex, DataPackage *package);

    /**
     * @brief Engine main loop
     */
    void run();

    /**
     * @brief Provide handles for Meas instances
     * @return current available MO Handle
     */
    unsigned short generateHandle();

    /**
     * @brief Initialize software shutdown
     */
    void stopRunning();

    /**
     * Engine class is singleton
     */
    static Engine& getInstance();
};

inline void engineThread() {
    Engine::getInstance().run();
}

} /* namespace core */
#endif /* ENGINE_H_ */
